package com.zongtui.fourinone.delegate;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * 代理服务.【通过反射创建出新的对象来接收远程传递的对象】
 */
public class DelegateConsole implements InvocationHandler {
    /**
     * 对象组
     */
    private Object[] bs;

    /**
     * 构造函数.
     *
     * @param bs
     */
    private DelegateConsole(Object[] bs) {
        this.bs = bs;
    }

    /**
     * 绑定动作.
     *
     * @param as
     * @param bs
     * @return
     */
    public static Object bind(Class[] as, Object... bs) {

        return Proxy.newProxyInstance(as[0].getClassLoader(), as, new DelegateConsole(bs));
    }

    public static <I> I bind(Class<I> a, Object... bs) {
        return (I) bind(new Class[]{a}, bs);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        Object mbeginObj = null, mimplObj = null, mendObj = null;
        Method mbegin = null, mimpl = null, mend = null;

        for (Object b : bs) {
            Method[] bms = b.getClass().getMethods();
            for (Method bm : bms) {
                boolean anflag = bm.isAnnotationPresent(Delegate.class);
                if (anflag) {
                    Delegate dl = bm.getAnnotation(Delegate.class);
                    Class dlifl = Class.forName(dl.interfaceName());
                    if (dlifl.isAssignableFrom(proxy.getClass()) && dl.methodName().equals(method.getName()) && Arrays.equals(method.getParameterTypes(), bm.getParameterTypes()) && method.getReturnType().equals(bm.getReturnType())) {
                        DelegatePolicy dp = dl.policy();
                        if (dp == DelegatePolicy.Begin) {
                            mbeginObj = b;
                            mbegin = bm;
                        } else if (dp == DelegatePolicy.Implements) {
                            mimplObj = b;
                            mimpl = bm;
                        } else if (dp == DelegatePolicy.End) {
                            mendObj = b;
                            mend = bm;
                        }
                    }
                }
            }
        }

        if (mimpl != null) {
            if (mbegin != null)
                mbegin.invoke(mbeginObj, args);
            result = mimpl.invoke(mimplObj, args);
            if (mend != null)
                mend.invoke(mendObj, args);
        }
        return result;
    }

}